<?php

namespace App\Common;
use App\Exceptions\BusinessException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use InvalidArgumentException;
/**
 * jwt密钥生成解析类
 *
 * @author WangBin
 * @date 2021-08-12
 * @package App\Http\Common
 */
class JwtAuth
{
    private static $instance;

    //私钥，没有私钥不会认证通过
    private $secret;
    //令牌的过期时间
    private $tokenTtl = Constant::JWT_TTL;
    private $token;
    private $phone;
    private $issuer = 'sd.api.service';
    private $audience  = 'sd.token';


    /**
     * 验证token
     *
     * @return array|bool
     */
    public function validate()
    {
        $token = $this->token;
        if (!$token) {
            return false;
        }
        $parseData = [];
        try{
            $signer = new Sha256();

            $parser = new Parser();
            $parse = $parser->parse($token);

            // 先验证私钥
            if ($parse->verify($signer, $this->secret) === false) {
                return $parseData;
            } else {
                $parseData = [
                    'writeOffPhone' => $parse->getClaim("writeOffPhone"),
                    'expired_at' => $parse->getClaim('exp'),
                ];
            }
        }catch (InvalidArgumentException | \RuntimeException $e){
            return $parseData;
        }
        return $parseData;
    }

    /**
     * 校验客户 token，成功返回解析数据
     *
     * @return array|bool
     * @throws BusinessException
     */
    public function verify()
    {
        $data = $this->validate();

        if(empty($data)) {
            throw new BusinessException(ResponseCode::API_AUTH_FAIL);
        }

        if($data['expired_at'] < Tools::getSec()) {
            throw new BusinessException(ResponseCode::API_AUTH_FAIL);
        }
        return $data;
    }

    /**
     * 生成 token
     *
     * @return $this
     * @throws BusinessException
     */
    public function encode()
    {
        try {
            $builder = new Builder();
            $signer = new Sha256();
            //发布端url颁发者
            $builder->setIssuer($this->issuer);
            //请求端URL访问群体
            $builder->setAudience($this->audience);
            //唯一的jwt id作为头项复制
            $builder->setId("sd-token-server", true);
            //配置颁发令牌的时间
            $builder->setIssuedAt(time());
            //令牌可以使用的时间
            $builder->setNotBefore(time() + 5);
            //令牌的过期时间
            $builder->setExpiration(time() + $this->tokenTtl);
            //配置核销人员手机号
            $builder->set('writeOffPhone', $this->phone);
            //使用“$this->secret”作为密钥创建签名
            $builder->sign($signer, $this->secret);
            //生成的令牌
            $token = $builder->getToken();
            if(empty($token)) {
                throw new \Exception('获取token失败');
            }
            $this->token = (string)$token;
            return $this;
        } catch (\Exception $exception) {
            throw new BusinessException(ResponseCode::JWT_MAKE_FAIL);
        }
    }

    /**
     * 单例模式 禁止该类在外部被new
     *
     * JwtAuth constructor.
     */
    private function __construct()
    {
        $this->secret = config('jwt.secret', 'aAbBcCzZ_000_111_222@123@#');
    }

    /**
     * 获取token
     *
     * @return string
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * 设置token
     *
     * @param string $token
     * @return
     */
    public function setToken(string $token)
    {
        $this->token = $token;
        return $this;
    }

    /**
     * @return mixed
     */
    public function getWriteOffPhone()
    {
        return $this->phone;
    }

    /**
     * 设置手机号
     * @param string $phone
     * @return $this
     */
    public function setWriteOffPhone(string $phone)
    {
        $this->phone = $phone;
        return $this;
    }

    /**
     * 该类的实例
     *
     * @return JwtAuth
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 单例模式 禁止外部克隆
     */
    private function __clone(){}
}
